Laplacian Smoothing and Mesh Dual¶

This notebook contains an exercise where you

  • smooth a mesh by replacing each vertex with the average of its neighbors.
  • compute the volume of a tetrahedral mesh
  • compute the dual of a mesh by converting each vertex to a face such that the vertices of the new face correspond to the faces of the old mesh.
In [ ]:
from pygel3d import hmesh, jupyter_display as jd
from numpy import zeros
from numpy.linalg import det
jd.set_export_mode(True)
def mesh_stats(m):
    print("# faces : ", m.no_allocated_faces(), " # vertices : ", m.no_allocated_vertices())

m = hmesh.load("bunnygtest.obj")

Problem 1: Insert code to complete the smoothing function¶

In [ ]:
def smooth(m, max_iter=1):
    # max_iter: the amount smoothing iterations
    
    pos = m.positions()
    new_pos = zeros(pos.shape)
    
    for _ in range(0, max_iter):
        
        for v in m.vertices():
            sum = 0
            # visit neighbouring vertices and add their positions
            for n in m.circulate_vertex(v):
                sum += pos[n]
            avg = sum / m.valency(v)
            new_pos[v] = avg
            
        # update the positions of the mesh to the average positions
        pos[:] = new_pos
    
    return m

Problem 2: Insert code to compute the volume of a triangle mesh¶

In [ ]:
import numpy as np

def calculate_volume(m):
    pos = m.positions()
    vol = 0
    # Insert code ------>
    for f in m.faces():
        N = m.circulate_face(f, 'v')
        vol += np.linalg.det([pos[n] for n in N]) / 6
    # <------------------
    return vol

print("Volume: ", calculate_volume(m))
Volume:  0.0007541261586712999

Problem 3: Insert code to complete the dual function¶

In [ ]:
def dual(m):
    """
    The dual of a mesh is a new mesh constructed 
    from the original mesh where vertices become 
    faces and faces become vertices.
    
    The dual of a 2-manifold polygonal mesh without boundary is com-
    monly defined as another mesh with the same topology (genus)
    but different connectivity (vertex-face incidence), in which faces
    and vertices occupy complementary locations and the position of
    each dual vertex is computed as the center of mass (barycenter or
    centroid) of the vertices that support the corresponding face.
    """
    m2 = hmesh.Manifold()
    # Insert code ------>
    for v in m.vertices():
        dual_vertices = []
        fs = m.circulate_vertex(v, 'f')
        
        # dual_vertices consist of the barycenter (or centroid) of the vertices that support the corresponding face
        dual_vertices.extend(m.centre(f) for f in fs)
        m2.add_face(dual_vertices)
    # <------------------
    return m2

Show original mesh¶

If you don't see anything it is probably a problem with the path to data/bunnygtest.obj. The path should be relative to the current working directory: probably this is the directory that Jupyter Notebook shows when it starts.

In [ ]:
m = hmesh.load("bunnygtest.obj")
mesh_stats(m)
print("Volume: ", calculate_volume(m))
jd.display(m)
# faces :  6966  # vertices :  3485
Volume:  0.0007541261586712999

Show the smoothed mesh¶

In [ ]:
m_s = hmesh.Manifold(m)
smooth(m_s,50)
print("Volume: ", calculate_volume(m))
jd.display(m_s)
Volume:  0.0007541261586712999

Show the dual mesh¶

In [ ]:
mesh_stats(m)
m_d = dual(m)
mesh_stats(m_d)
jd.display(m_d)
# faces :  6966  # vertices :  3485
# faces :  3485  # vertices :  20898

When everything works, export this to an HTML file and submit that!